/*
 * tagfile.c
 * 
 * Created on: Apr 2, 2009
 * Author: cauan
 *
 * Compile with:
 * gcc -Wall `pkg-config fuse --cflags --libs` -lsqlite3  tagfile.c -o tagfile
 *
 * OSX
 * Should install macfuse from macports
 *
 */

#define FUSE_USE_VERSION 26

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

#include <stdlib.h>
#include <sqlite3.h>
#include "sql.c"
#include <signal.h>

static const char *tf_str = "Hello World!\n";
static const char *tf_path = "/aloha";

char *get_tag_name(const char *path) {
	char *idx = rindex(path, '/');
	if (idx == NULL)
		return "";
	char *tagname = strdup (++idx);
	return tagname;
}

char *rtrim_path (const char *path){
	char *tmp1 = rindex(path, '/');
	char *tmp2 = calloc( strlen(path) - ( path - tmp1 ), sizeof(char));
	strncpy (tmp2, path, tmp1 - path);
	return tmp2;
}

char *get_parent_name(const char *path) {
	char *tmp = calloc(strlen(path), sizeof(char));
	tmp = rtrim_path(path);
	char *parent = calloc(strlen(tmp), sizeof(char));
	parent = get_tag_name(tmp);
	free (tmp);
	return parent;
}

static int tf_getattr(const char *path, struct stat *stbuf) {
	int res = -ENOENT;
	memset(stbuf, 0, sizeof(struct stat));

	char query[512];
	snprintf(query,sizeof(query), SELECT_TAG, get_tag_name(path));
	
	sqlite3_stmt *stmt;
	sqlite3_prepare(db, query, -1, &stmt, 0);
	while (sqlite3_step(stmt) == SQLITE_ROW){
		stbuf->st_mode = S_IFDIR | 0755;
		stbuf->st_nlink = 2;
		res = 0;
	};

/*
	if (strcmp(path, tf_path) == 0) {
		stbuf->st_mode = S_IFREG | 0444;
		stbuf->st_nlink = 1;
		stbuf->st_size = strlen(tf_str);
	}
*/
	return res;
}

static int tf_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
			off_t offset, struct fuse_file_info *fi) {
	(void) offset;
	(void) fi;
	
	filler(buf, ".", NULL, 0);
	filler(buf, "..", NULL, 0);

	char query[512];
	snprintf(query, sizeof(query), LIST_TAG, get_tag_name(path));
	
	sqlite3_stmt *stmt;
	sqlite3_prepare(db, query, -1, &stmt, 0);
	while (sqlite3_step(stmt) == SQLITE_ROW)
		filler(buf, (char *)sqlite3_column_text(stmt,0), NULL, 0);
	return 0;
}

static int tf_open(const char *path, struct fuse_file_info *fi) {
	if (strncmp(path, tf_path, sizeof(path)) != 0)
		return -ENOENT;
	
	if ((fi->flags & 3) != O_RDONLY)
		return -EACCES;
		
	return 0;
}

static int tf_read(const char *path, char *buf, size_t size, off_t offset,
			struct fuse_file_info *fi) {
	size_t len;
	(void) fi;
	if(strncmp(path, tf_path, sizeof(path)) != 0)
		return -ENOENT;
	
	len = strlen(tf_str);
	if (offset < len) {
		if (offset + size > len)
			size = len - offset;
		memcpy(buf, tf_str + offset, size);
	} else
		size = 0;
	
	return size;
}

static int tf_mkdir(const char *path, mode_t mode) {
	int res;

	char query[512];
	snprintf (query, sizeof(query), CREATE_TAG, get_tag_name(path),get_parent_name(path), get_tag_name(path));
	res = sql_exec (db, query, NULL);
	if(res == -1)
		return -errno;
	
	return 0;
}


static struct fuse_operations tf_oper = {
	.getattr	= tf_getattr,
	.readdir	= tf_readdir,
	.mkdir	= tf_mkdir,
	.open	= tf_open,
	.read	= tf_read,
};

int main(int argc, char *argv[]) {
	
	// Open DB
	int db_status = sqlite3_open("/tmp/base.sqlite3", &db);
	if ( db_status != 0 ) {
		printf ("Error: database could not be open.");
		return 1;
	}

	// Initialize DB
	sql_exec (db, CREATE_TABLE_TAG,NULL );
	sql_exec (db, CREATE_TABLE_TAG_TAG,NULL );
	sql_exec (db, CREATE_ROOT,NULL );

	//signal(2,  sql_exit(0) ); /* SIGINT */
	//signal(11, sql_exit(0) ); /* SIGSEGV */
	//signal(15, sql_exit(0) ); /* SIGTERM */

	return fuse_main(argc, argv, &tf_oper, NULL);
}
